package io.kiki.stack.netty.command;

import io.kiki.stack.netty.config.switches.ProtocolSwitch;
import io.kiki.stack.netty.exception.DeserializationException;
import io.kiki.stack.netty.exception.SerializationException;
import io.kiki.stack.netty.invoker.RequestContext;
import io.kiki.stack.netty.protocol.DeserializeLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Setter
@Getter
public abstract class AbstractCommand implements Command {

    private static final long serialVersionUID = 1L;
    private CommandCode commandCode;

    private byte type;


    private ProtocolSwitch protocolSwitch = new ProtocolSwitch();
    private int id;

    private short clazzLength = 0;
    private short headerLength = 0;
    private int contentLength = 0;

    private byte[] clazz;

    private byte[] header;

    private byte[] content;

    private RequestContext requestContext;

    public AbstractCommand() {
    }

    public AbstractCommand(byte type) {
        this();
        this.type = type;
    }

    public AbstractCommand(CommandCode commandCode) {
        this();
        this.commandCode = commandCode;
    }

    public AbstractCommand(byte type, CommandCode commandCode) {
        this(commandCode);
        this.type = type;
    }


    @Override
    public void serialize() throws SerializationException {
        this.serializeClazz();
        this.serializeHeader(this.requestContext);
        this.serializeContent(this.requestContext);
    }

    @Override
    public void deserialize() throws DeserializationException {
        this.deserializeClazz();
        this.deserializeHeader(this.requestContext);
        this.deserializeContent(this.requestContext);
    }

    /**
     * Deserialize according to mask.
     * <ol>
     *     <li>If mask <= {@link DeserializeLevel#deserialize_clazz}, only deserialize clazz - only one part.</li>
     *     <li>If mask <= {@link DeserializeLevel#deserialize_header}, deserialize clazz and header - two parts.</li>
     *     <li>If mask <= {@link DeserializeLevel#deserialize_all}, deserialize clazz, header and content - all three parts.</li>
     * </ol>
     */
    public void deserialize(long mask) throws DeserializationException {
        if (mask <= DeserializeLevel.deserialize_clazz) {
            this.deserializeClazz();
        } else
            if (mask <= DeserializeLevel.deserialize_header) {
                this.deserializeClazz();
                this.deserializeHeader(this.getRequestContext());
            } else
                if (mask <= DeserializeLevel.deserialize_all) {
                    this.deserialize();
                }
    }


    public void serializeClazz() throws SerializationException {

    }


    public void deserializeClazz() throws DeserializationException {

    }


    public void serializeHeader(RequestContext requestContext) throws SerializationException {
    }

    public void deserializeHeader(RequestContext requestContext) throws DeserializationException {
    }

    @Override
    public void serializeContent(RequestContext requestContext) throws SerializationException {
    }


    @Override
    public void deserializeContent(RequestContext requestContext) throws DeserializationException {
    }


    @Override
    public CommandCode getCommandCode() {
        return commandCode;
    }


    @Override
    public RequestContext getRequestContext() {
        return requestContext;
    }


    @Override
    public ProtocolSwitch getProtocolSwitch() {
        return protocolSwitch;
    }


    @Override
    public int getId() {
        return id;
    }

    public void setClazz(byte[] clazz) {
        if (clazz != null) {
            if (clazz.length > Short.MAX_VALUE) {
                throw new RuntimeException("class length exceed maximum, len=" + clazz.length);
            }
            this.clazzLength = (short) clazz.length;
            this.clazz = clazz;
        }
    }

    public void setHeader(byte[] header) {
        if (header != null) {
            if (header.length > Short.MAX_VALUE) {
                throw new RuntimeException("header length exceed maximum, len=" + header.length);
            }
            this.headerLength = (short) header.length;
            this.header = header;
        }
    }


    public void setContent(byte[] content) {
        if (content != null) {
            this.contentLength = content.length;
            this.content = content;

        }
    }


}
